package com.huaboot.framework.security.config;

import com.huaboot.framework.security.exception.SecurityAuthenticationEntryPoint;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpMethod;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.AuthenticationProvider;
import org.springframework.security.authentication.DefaultAuthenticationEventPublisher;
import org.springframework.security.authentication.ProviderManager;
import org.springframework.security.authentication.dao.DaoAuthenticationProvider;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configurers.AbstractHttpConfigurer;
import org.springframework.security.config.annotation.web.configurers.HeadersConfigurer;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import org.springframework.web.filter.OncePerRequestFilter;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.util.ArrayList;
import java.util.List;

/**
 * @Author ff
 * @Date 2023/8/24 10:19 下午
 * @Version 1.0
 */
@Configuration
@EnableWebSecurity
public class SecurityConfig {
    @Autowired
    private PasswordEncoder passwordEncoder;

    @Autowired
    private OncePerRequestFilter authenticationTokenFilter;

    @Resource
    private  UserDetailsService userDetailsService;

    @Autowired
    private ApplicationEventPublisher applicationEventPublisher;



    /**
     * 提供的一个身份验证提供者
     * 设置加密的方式
     * 设置获取用户的详细方法类似回调里面放的是一个接口UserDetailsService
     * 我们在system包中实现接口，重写了loadUserByUsername方法来获取登录人信息
     * @return
     */
    @Bean
    DaoAuthenticationProvider daoAuthenticationProvider() {
        DaoAuthenticationProvider daoAuthenticationProvider = new DaoAuthenticationProvider();
        daoAuthenticationProvider.setPasswordEncoder(passwordEncoder);
        daoAuthenticationProvider.setUserDetailsService(userDetailsService);
        return daoAuthenticationProvider;
    }

    /**
     * 用于创建一个认证管理器（AuthenticationManager）
     * 用于处理身份验证请求，providerList用于存储各种身份验证提供者，如手机号验证、账号密码验证
     * 这段代码的意思是创建一个DaoAuthenticationProvider对象，并设置密码编码器和用户详细信息服务，
     * 然后将其作为Spring Bean进行管理，以供后续的身份验证使用。
     */
    @Bean
    public AuthenticationManager authenticationManager() {
        List<AuthenticationProvider> providerList = new ArrayList<>();
        providerList.add(daoAuthenticationProvider());
       // providerList.add(mobileAuthenticationProvider());
        ProviderManager providerManager = new ProviderManager(providerList);
        providerManager.setAuthenticationEventPublisher(new DefaultAuthenticationEventPublisher(applicationEventPublisher));
        return providerManager;
    }

    @Bean
    SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
        // 忽略授权的地址列表
        //List<String> permitList = permitResource.getPermitList();

        List<String> permitList = new ArrayList<>();
        permitList.add("/actuator/**");
        permitList.add("/v3/api-docs/**");
        permitList.add("/webjars/**");
        permitList.add("swagger/**");
        permitList.add("/swagger-resources/**");
        permitList.add("/swagger-ui.html");
        permitList.add("/swagger-ui/**");
        permitList.add("/doc.html");
        permitList.add("/system/auth/login");
        permitList.add("/system/auth/captcha/enabled");
        permitList.add("/system/auth/token");

        String[] permits = permitList.toArray(new String[0]);
        http
                .addFilterBefore(authenticationTokenFilter, UsernamePasswordAuthenticationFilter.class)
                .sessionManagement(session -> session.sessionCreationPolicy(SessionCreationPolicy.STATELESS))
                .authorizeHttpRequests(auth -> auth
                        .antMatchers(permits).permitAll()   // 通过 permits 允许的请求无需身份验证
                        .antMatchers(HttpMethod.OPTIONS).permitAll() // OPTIONS 请求无需身份验证
                        .anyRequest().authenticated()
                )
                .exceptionHandling(exception -> exception.authenticationEntryPoint(new SecurityAuthenticationEntryPoint()))
                .headers(headers -> headers.frameOptions(HeadersConfigurer.FrameOptionsConfig::disable))
                .csrf(AbstractHttpConfigurer::disable)
        ;

        return http.build();
    }
}
